package la.iok.hzsvn.lewin.movie.operation.service;

import com.wechat.pay.java.core.RSAConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSANotificationConfig;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.*;
import la.iok.hzsvn.lewin.movie.operation.entity.ChargeOrder;
import la.iok.hzsvn.lewin.movie.operation.model.ChargeOrderInfo;
import la.iok.hzsvn.share.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;

@Service
public class WxPayService implements PayService {
    private static final Logger logger = LoggerFactory.getLogger(WxPayService.class);
    private final WxConfigBean wxConfigBean;

    public WxPayService(WxConfigBean wxConfigBean) {
        this.wxConfigBean = wxConfigBean;
    }
    /**
     * native下单
     * @param order 订单
     */
    @Override
    public String prepare(@NotNull ChargeOrderInfo order) {
        PrepayRequest request = new PrepayRequest();
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        // 调用接口
        Amount amount = new Amount();
        amount.setTotal(order.getAmount());
        request.setAmount(amount);
        request.setAppid(wxConfigBean.appId());
        request.setMchid(wxConfigBean.merchantId());
        request.setDescription(order.description());
        request.setOutTradeNo(order.orderId());
        request.setNotifyUrl(wxConfigBean.notifyUrl("/operation/wx/notify"));
        PrepayResponse res =  getService().prepay(request);
        return res.getCodeUrl();
    }

    @Override
    public void closeOrder(ChargeOrderInfo order) {
        CloseOrderRequest request = new CloseOrderRequest();
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        request.setMchid(wxConfigBean.merchantId());
        request.setOutTradeNo(order.orderId());
        // 调用接口
        getService().closeOrder(request);
    }

    @Override
    public void queryOrder(ChargeOrderInfo order) {
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setMchid(wxConfigBean.merchantId());
        request.setOutTradeNo(order.orderId());
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        // 调用接口
        Transaction transaction = getService().queryOrderByOutTradeNo(request);
        if(transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS){
            order.setState(ChargeOrder.STATE_PAID);
            order.setEndTime(parseTime(transaction.getSuccessTime()));
        }else if(transaction.getTradeState() == Transaction.TradeStateEnum.NOTPAY){
            //未支付
        }else if(transaction.getTradeState() == Transaction.TradeStateEnum.CLOSED){
            order.setState(ChargeOrder.STATE_CLOSED);
        }else if(transaction.getTradeState() == Transaction.TradeStateEnum.REFUND){
            order.setState(ChargeOrder.STATE_REFUND);
        }
    }

    @Override
    public String notify(@NotNull String notification,@NotNull String signature,@NotNull String serialNumber,
                              @NotNull String nonce,@NotNull String timestamp) {
        RSANotificationConfig config = new RSANotificationConfig.Builder().apiV3Key(wxConfigBean.apiKey()).certificates(wxConfigBean.getX509Certificate()).build();
        NotificationParser parser = new NotificationParser(config);
        RequestParam param = new RequestParam.Builder().serialNumber(serialNumber).nonce(nonce).timestamp(timestamp).body(notification).signature(signature).build();
        Transaction transaction = parser.parse(param, Transaction.class);
        return transaction.getOutTradeNo();
    }

    private Date parseTime(String time){
        try{
            String pattern = "yyyy-MM-dd'T'HH:mm:ssX";
            return new SimpleDateFormat(pattern).parse(time);
        }catch (Exception e){
            logger.error("解析日期失败",e);
            return null;
        }
    }

    private NativePayService getService() {
        X509Certificate certificate = wxConfigBean.getX509Certificate();
        RSAConfig config = new RSAConfig.Builder().privateKey(wxConfigBean.privateKey()).merchantId(wxConfigBean.merchantId())
                .merchantSerialNumber(wxConfigBean.merchantSerialNumber()).wechatPayCertificates(certificate).build();
        return new NativePayService.Builder().config(config).build();
    }
}
